﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using WebApplicationFileSys.Filter;
using WebApplicationFileSys.Models;

namespace WebApplicationFileSys.Controllers
{
    /// <summary>
    /// 文件上传处理
    /// </summary>
    /// 添加时间：2023-8-31 18:00:46
    public class FileController : Controller
    {
        // 视图
        public ActionResult Preview()
        {
            return View();
        }

        //private ActionResult ValidUser()
        //{
        //    var userLogin = Session[KeyValueConfig.KeyUserSession];
        //    string adminAccount = System.Configuration.ConfigurationManager.AppSettings["user_admin"];
        //    bool isAdmin = userLogin.Equals(adminAccount);
        //    if (!isAdmin)
        //    {
        //        Response.StatusCode = 403;
        //        return Content("你无权访问");
        //    }
        //}

        // 视图，上传页面
        [LoginFilter(Roles = "admin")]
        public ActionResult Upload(string dir)
        {
            ViewBag.dir = dir;
            return View();
        }

        //创建文件夹
        //添加时间：2023-9-13 13:52:06，
        [LoginFilter(Roles = "admin")]
        public ActionResult MkdirFolder(string folder, string dir)
        {
            if (string.IsNullOrWhiteSpace(folder))
            {
                return Json(new Result("文件夹名称不可为空"));
            }
            //if (string.IsNullOrWhiteSpace(dir))
            //{
            //    ////dir = KeyValueConfig.fileSaveDir;
            //    //return Json(new Result("dir不可为空"));
            //}

            //文件夹名称，（英文符号）不允许包含\ / : * ? “ < > |
            bool right = folder.Contains("\\")
                                || folder.Contains("/")
                                || folder.Contains(":")
                                || folder.Contains("*")
                                || folder.Contains("?")
                                || folder.Contains("\"")
                                || folder.Contains("<")
                                || folder.Contains(">")
                                || folder.Contains("|");
            if (right)
            {
                return Json(new Result("文件夹名称，（英文符号）不允许包含\\ / : * ? “ < > |"));
            }
            object data = null;
            try
            {
                folder= folder.Trim();
                if (!string.IsNullOrWhiteSpace(dir))
                {
                    dir = dir.Trim();
                }
                string dirNew = Path.Combine(KeyValueConfig.fileSaveDir, dir, folder);
                if (System.IO.Directory.Exists(dirNew))
                {
                    return Json(new Result("已存在，不用创建", 1, 1));
                }
                else
                {
                    System.IO.Directory.CreateDirectory(dirNew);
                    return Json(new Result("创建成功", 1, 2));
                }
            }
            catch (Exception ex)
            {
                var ex1 = ex.InnerException ?? ex;
                return Json(new Result(ex1.Message));
            }
        }

        /// <summary>
        /// 并发合并检查
        /// </summary>
        static ConcurrentDictionary<string, string> checkMergeFile = new ConcurrentDictionary<string, string>();



        ////await Task.Yied
        //文件上传，处理
        [HttpPost]
        [LoginFilter(Roles = "admin")]
        public async Task<ActionResult> DoUpload()
        {
            //从Request中取参数，注意上传的文件在Requst.Files中
            string name = Request["name"];
            int total = Convert.ToInt32(Request["total"]);
            int index = Convert.ToInt32(Request["index"]);
            var data = Request.Files["data"];

            //当前文件夹
            string referrerQuery = Request.UrlReferrer.Query;
            referrerQuery = System.Web.HttpUtility.UrlDecode(referrerQuery);
            string dirCurrent = referrerQuery.Replace("?dir=", "");

            await Task.Yield();

            try
            {
                //保存一个分片到磁盘上
                //string dirRoot = Server.MapPath("~/Upload");
                string dirRoot = KeyValueConfig.fileSaveDir;
                string extend = Path.GetExtension(name).ToString();

                //普通文件保存目录
                string dir = Path.Combine(dirRoot, dirCurrent);

                ////图片保存目录
                //if (".jpg^.jpeg^.png^.gif^.bmp^.ico^.webp".Contains(extend))
                //{
                //    dir = Path.Combine(dirRoot, "img", DateTime.Now.ToString("yyyy_MM"));
                //}
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }

                string file = Path.Combine(dir, name + "_" + index);
                data.SaveAs(file);

                //最后一个分片文件，开始合并
                if (total == index)
                {
                    Task.Run(() =>
                    {
                        //判断是否已经有此文件在合并了，处理并发合并情况
                        bool isMerge = checkMergeFile.Values.Contains(name);
                        if (isMerge)
                        {
                            LogHelpter.AddLog("阻止了一次并发合并文件", null, "Merge_conflict");
                            return;
                        }

                        //等待文件数 对齐总分片
                        while (true)
                        {
                            string[] files2 = Directory.GetFiles(dir, name + "_*");
                            LogHelpter.AddLog($"while----{name}，total=" + total + "，接收文件数=" + files2.Length);
                            if (files2.Length == total)
                            {
                                break;
                            }
                            System.Threading.Thread.Sleep(1000);
                        }

                        //计时
                        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
                        stopwatch.Start();

                        string chKey = Guid.NewGuid().ToString("N");
                        checkMergeFile.TryAdd(chKey, name);
                        LogHelpter.AddLog("checkMergeFile个数" + checkMergeFile.Count + ",开始合并...");

                        file = Path.Combine(dir, name);
                        var fs = new FileStream(file, FileMode.Create);
                        for (int i = 1; i <= total; ++i)
                        {
                            string part = Path.Combine(dir, name + "_" + i);
                            var bytes = System.IO.File.ReadAllBytes(part);
                            fs.Write(bytes, 0, bytes.Length);
                            bytes = null;
                            System.IO.File.Delete(part);
                        }
                        fs.Close();
                        fs.Dispose();
                        string outValue = string.Empty;
                        checkMergeFile.TryRemove(chKey, out outValue);

                        stopwatch.Stop();
                        LogHelpter.AddLog($"{name} 合并耗时（毫秒）{stopwatch.ElapsedMilliseconds}");

                    });

                    //数据库保存相对路径，生产环境一般存英文，  比如/upload/123444.jpg
                    //string dbFileUrl = "/" + file.Replace(AppDomain.CurrentDomain.BaseDirectory, "").Replace(@"\", "/");
                    string dbFileUrl = "/" + file.Replace(AppDomain.CurrentDomain.BaseDirectory, "").Replace(@"\", "/").Replace("_" + index, "");

                    //最后一个分片，返回相对url，用于数据库保存， 
                    return Json(new { Code = 0, Msg = "上传成功", url = dbFileUrl });
                }

                //返回是否成功，此处做了简化处理
                return Json(new { Code = 0, Msg = "上传成功" });
            }
            catch (Exception ex)
            {
                return Json(new { Code = 1, Msg = ex.ToString() });
            }
        }




    }
}